using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace WaterQualityReportSystem.utils
{
    public class ModBusRTUHelper
    {
        /// <summary>
        /// 计算 ModBus-RTU CRC16 校验码
        /// </summary>
        /// <param name="data">要计算校验码的数据</param>
        /// <returns>CRC16 校验码</returns>
        public static ushort CalculateCRC16(byte[] data)
        {
            ushort crc = 0xFFFF;
            
            for (int i = 0; i < data.Length; i++)
            {
                crc ^= data[i];
                
                for (int j = 0; j < 8; j++)
                {
                    if ((crc & 0x0001) != 0)
                    {
                        crc >>= 1;
                        crc ^= 0xA001;
                    }
                    else
                    {
                        crc >>= 1;
                    }
                }
            }
            
            return crc;
        }

        /// <summary>
        /// 生成读取硬度数据的 ModBus-RTU 命令
        /// </summary>
        /// <param name="deviceAddress">设备地址（默认 0x01）</param>
        /// <returns>完整的 ModBus-RTU 命令字节数组</returns>
        public static byte[] GenerateReadHardnessCommand(byte deviceAddress = 0x01)
        {
            // 命令格式：01 03 00 16 00 02 25 CF
            // 01: 设备地址
            // 03: 功能码（读取保持寄存器）
            // 00 16: 起始地址（22 = 0x16）
            // 00 02: 寄存器数量（2个寄存器，用于32位浮点数）
            // 25 CF: CRC16校验码
            
            byte[] command = new byte[8];
            command[0] = deviceAddress;  // 设备地址
            command[1] = 0x03;           // 功能码
            command[2] = 0x00;           // 起始地址高字节
            command[3] = 0x16;           // 起始地址低字节（22）
            command[4] = 0x00;           // 寄存器数量高字节
            command[5] = 0x02;           // 寄存器数量低字节（2个寄存器）
            
            // 计算CRC16校验码
            ushort crc = CalculateCRC16(command, 0, 6);
            command[6] = (byte)(crc & 0xFF);        // CRC低字节
            command[7] = (byte)((crc >> 8) & 0xFF); // CRC高字节
            
            return command;
        }

        /// <summary>
        /// 计算 ModBus-RTU CRC16 校验码（指定范围）
        /// </summary>
        /// <param name="data">数据数组</param>
        /// <param name="offset">起始偏移</param>
        /// <param name="length">长度</param>
        /// <returns>CRC16 校验码</returns>
        private static ushort CalculateCRC16(byte[] data, int offset, int length)
        {
            ushort crc = 0xFFFF;
            
            for (int i = offset; i < offset + length; i++)
            {
                crc ^= data[i];
                
                for (int j = 0; j < 8; j++)
                {
                    if ((crc & 0x0001) != 0)
                    {
                        crc >>= 1;
                        crc ^= 0xA001;
                    }
                    else
                    {
                        crc >>= 1;
                    }
                }
            }
            
            return crc;
        }

        /// <summary>
        /// 解析硬度检测仪返回的数据
        /// </summary>
        /// <param name="responseData">设备返回的原始数据</param>
        /// <returns>解析后的硬度值，如果解析失败返回 null</returns>
        public static float? ParseHardnessResponse(byte[] responseData)
        {
            try
            {
                // 检查数据长度和格式
                // 期望格式：01 03 04 42 B0 5C 4F 97 58
                // 01: 设备地址
                // 03: 功能码
                // 04: 数据字节数
                // 42 B0 5C 4F: 32位浮点数数据（Big-Endian）
                // 97 58: CRC16校验码
                
                if (responseData.Length < 9)
                {
                    return null;
                }

                // 验证设备地址和功能码
                if (responseData[0] != 0x01 || responseData[1] != 0x03)
                {
                    return null;
                }

                // 验证数据字节数
                if (responseData[2] != 0x04)
                {
                    return null;
                }

                // 验证CRC校验码
                ushort receivedCrc = (ushort)((responseData[8] << 8) | responseData[7]);
                ushort calculatedCrc = CalculateCRC16(responseData, 0, 7);
                
                if (receivedCrc != calculatedCrc)
                {
                    return null;
                }

                // 提取32位浮点数数据（Big-Endian格式）
                byte[] floatBytes = new byte[4];
                floatBytes[0] = responseData[3]; // 最高位字节
                floatBytes[1] = responseData[4];
                floatBytes[2] = responseData[5];
                floatBytes[3] = responseData[6]; // 最低位字节

                // 转换为浮点数（Big-Endian）
                float hardnessValue = BitConverter.ToSingle(floatBytes.Reverse().ToArray(), 0);

                return hardnessValue;
            }
            catch (Exception)
            {
                return null;
            }
        }

        /// <summary>
        /// 生成读取设备运行状态的 ModBus-RTU 命令
        /// </summary>
        /// <param name="deviceAddress">设备地址（默认 0x01）</param>
        /// <returns>完整的 ModBus-RTU 命令字节数组</returns>
        public static byte[] GenerateReadDeviceStatusCommand(byte deviceAddress = 0x01)
        {
            // 命令格式：01 04 03 84 00 02 20 66
            // 01: 设备地址
            // 04: 功能码（读取输入寄存器）
            // 03 84: 起始地址（900 = 0x0384）
            // 00 02: 寄存器数量（2个寄存器：900运行状态，901报警状态）
            // 20 66: CRC16校验码
            
            byte[] command = new byte[8];
            command[0] = deviceAddress;  // 设备地址
            command[1] = 0x04;           // 功能码
            command[2] = 0x03;           // 起始地址高字节
            command[3] = 0x84;           // 起始地址低字节（900）
            command[4] = 0x00;           // 寄存器数量高字节
            command[5] = 0x02;           // 寄存器数量低字节（2个寄存器）
            
            // 计算CRC16校验码
            ushort crc = CalculateCRC16(command, 0, 6);
            command[6] = (byte)(crc & 0xFF);        // CRC低字节
            command[7] = (byte)((crc >> 8) & 0xFF); // CRC高字节
            
            return command;
        }

        /// <summary>
        /// 解析设备状态响应数据
        /// </summary>
        /// <param name="responseData">设备返回的原始数据</param>
        /// <returns>设备状态信息，如果解析失败返回 null</returns>
        public static DeviceStatusInfo ParseDeviceStatusResponse(byte[] responseData)
        {
            try
            {
                // 检查数据长度和格式
                // 期望格式：01 04 04 00 00 00 02 38 F1
                // 01: 设备地址
                // 04: 功能码（读取输入寄存器）
                // 04: 数据字节数（4字节数据）
                // 00 00: 运行状态（寄存器900）
                // 00 02: 报警状态（寄存器901）
                // 38 F1: CRC16校验码
                
                if (responseData.Length < 9)
                {
                    return null;
                }

                // 验证设备地址和功能码
                if (responseData[0] != 0x01 || responseData[1] != 0x04)
                {
                    return null;
                }

                // 验证数据字节数
                if (responseData[2] != 0x04)
                {
                    return null;
                }

                // 验证CRC校验码
                ushort receivedCrc = (ushort)((responseData[8] << 8) | responseData[7]);
                ushort calculatedCrc = CalculateCRC16(responseData, 0, 7);
                
                if (receivedCrc != calculatedCrc)
                {
                    return null;
                }

                // 提取状态数据（ModBus-RTU 寄存器数据为16位，高字节在前）
                int operatingStatus = (responseData[3] << 8) | responseData[4]; // 运行状态（寄存器900）
                int alarmStatus = (responseData[5] << 8) | responseData[6];     // 报警状态（寄存器901）

                return new DeviceStatusInfo
                {
                    OperatingStatus = operatingStatus,
                    AlarmStatus = alarmStatus,
                    IsValid = true
                };
            }
            catch (Exception)
            {
                return null;
            }
        }

        /// <summary>
        /// 获取运行状态描述
        /// </summary>
        /// <param name="status">运行状态值</param>
        /// <returns>状态描述</returns>
        public static string GetOperatingStatusDescription(int status)
        {
            switch (status)
            {
                case 0: return "等待";
                case 1: return "正在取样";
                case 2: return "停止取样";
                case 3: return "首次加药";
                case 4: return "正在滴定";
                case 5: return "正在清洗";
                default: return $"未知状态({status})";
            }
        }

        /// <summary>
        /// 获取报警状态描述
        /// </summary>
        /// <param name="status">报警状态值</param>
        /// <returns>状态描述</returns>
        public static string GetAlarmStatusDescription(int status)
        {
            switch (status)
            {
                case 0: return "正常";
                case 1: return "无水或无试剂";
                case 2: return "水样没清洗干净";
                case 3: return "正在滴定根据加药时长超时报警";
                case 4: return "正在滴定, 比较实时测量值大于试剂最大值报警";
                case 5: return "正在滴定, 比较实时测量值小于试剂最小值报警, 停机";
                case 6: return "无新水进入, 比色皿内颜色深(检测异常)";
                case 8: return "检测试剂小于5%报警";
                case 9: return "通讯异常";
                default: return $"未知报警({status})";
            }
        }

        /// <summary>
        /// 检查是否为有效的 ModBus-RTU 响应
        /// </summary>
        /// <param name="data">接收到的数据</param>
        /// <returns>是否为有效的 ModBus-RTU 响应</returns>
        public static bool IsValidModBusResponse(byte[] data)
        {
            if (data.Length < 5)
            {
                return false;
            }

            // 检查功能码
            if (data[1] != 0x03 && data[1] != 0x04)
            {
                return false;
            }

            // 检查数据长度
            int expectedLength = 3 + data[2] + 2; // 地址(1) + 功能码(1) + 字节数(1) + 数据(n) + CRC(2)
            if (data.Length < expectedLength)
            {
                return false;
            }

            // 验证CRC校验码
            ushort receivedCrc = (ushort)((data[data.Length - 1] << 8) | data[data.Length - 2]);
            ushort calculatedCrc = CalculateCRC16(data, 0, data.Length - 2);
            
            return receivedCrc == calculatedCrc;
        }

        /// <summary>
        /// 生成设备状态响应数据
        /// </summary>
        /// <param name="operatingStatus">运行状态 (0-5)</param>
        /// <param name="alarmStatus">报警状态 (0-9)</param>
        /// <param name="deviceAddress">设备地址 (默认 0x01)</param>
        /// <returns>十六进制字符串格式的状态响应数据</returns>
        public static string GenerateDeviceStatusResponse(int operatingStatus, int alarmStatus, byte deviceAddress = 0x01)
        {
            // 构建 ModBus-RTU 状态响应数据
            // 格式: 设备地址(1) + 功能码(1) + 字节数(1) + 运行状态(2) + 报警状态(2) + CRC16(2)
            byte[] response = new byte[9];
            response[0] = deviceAddress;        // 设备地址
            response[1] = 0x04;                 // 功能码 (读取输入寄存器)
            response[2] = 0x04;                 // 字节数（4字节数据）
            response[3] = (byte)((operatingStatus >> 8) & 0xFF);  // 运行状态高字节
            response[4] = (byte)(operatingStatus & 0xFF);         // 运行状态低字节
            response[5] = (byte)((alarmStatus >> 8) & 0xFF);      // 报警状态高字节
            response[6] = (byte)(alarmStatus & 0xFF);             // 报警状态低字节

            // 计算 CRC16 校验码
            byte[] dataForCrc = new byte[7];
            Array.Copy(response, 0, dataForCrc, 0, 7);
            ushort crc = CalculateCRC16(dataForCrc);
            response[7] = (byte)(crc & 0xFF);        // CRC 低字节
            response[8] = (byte)((crc >> 8) & 0xFF); // CRC 高字节

            // 转换为十六进制字符串
            return BitConverter.ToString(response).Replace("-", "");
        }

        /// <summary>
        /// 根据状态描述生成设备状态响应数据
        /// </summary>
        /// <param name="statusDescription">状态描述</param>
        /// <param name="deviceAddress">设备地址 (默认 0x01)</param>
        /// <returns>十六进制字符串格式的状态响应数据</returns>
        public static string GenerateDeviceStatusResponseByDescription(string statusDescription, byte deviceAddress = 0x01)
        {
            int operatingStatus = 0;
            int alarmStatus = 0;

            // 解析状态描述
            if (statusDescription.Contains("正在取样"))
                operatingStatus = 1;
            else if (statusDescription.Contains("停止取样"))
                operatingStatus = 2;
            else if (statusDescription.Contains("首次加药"))
                operatingStatus = 3;
            else if (statusDescription.Contains("正在滴定"))
                operatingStatus = 4;
            else if (statusDescription.Contains("正在清洗"))
                operatingStatus = 5;
            else
                operatingStatus = 0; // 等待

            if (statusDescription.Contains("无水或无试剂"))
                alarmStatus = 1;
            else if (statusDescription.Contains("水样没清洗干净"))
                alarmStatus = 2;
            else if (statusDescription.Contains("加药时长超时"))
                alarmStatus = 3;
            else if (statusDescription.Contains("检测异常"))
                alarmStatus = 6;
            else if (statusDescription.Contains("试剂不足"))
                alarmStatus = 8;
            else if (statusDescription.Contains("通讯异常"))
                alarmStatus = 9;
            else
                alarmStatus = 0; // 正常

            return GenerateDeviceStatusResponse(operatingStatus, alarmStatus, deviceAddress);
        }
    }

    /// <summary>
    /// 设备状态信息
    /// </summary>
    public class DeviceStatusInfo
    {
        public int OperatingStatus { get; set; }
        public int AlarmStatus { get; set; }
        public bool IsValid { get; set; }
    }
}